using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Reflection;
using System.Drawing;
using MacomberMap.Common.Logging;
using MacomberMap.Common.Internals;
using MacomberMap.Common.User_Interfaces.Components;
using MacomberMap.Common.Types;
using MacomberMap.Common.Components;
using System.Data.Common;
using MacomberMap.Common.Convertors;
using System.IO;
using MacomberMap.Common.User_Interfaces.One_Lines.Elements;
using MacomberMap.Common.Events;
using System.Collections;
using System.ComponentModel;
using MacomberMap.Common.Database_Interface;

namespace MacomberMap.Common.Types
{
    #region Target identification
    /// <summary>
    /// This class holds information on a serializable target
    /// </summary>
    public class MM_Serializable_Target : Attribute
    {
        #region Variable declarations
        /// <summary>
        /// The collection of possible target types
        /// </summary>
        [Flags]        
        public enum enumTargetType
        {
            /// <summary>Not a target</summary>
            None=0,
            /// <summary>Just in the elements table</summary>
            ElementCollection = 1,
            /// <summary>Just in the type-specific table</summary>
            TypeCollection = 2,
            /// <summary>In both the elements and type-specific table</summary>
            Both = 3,
            /// <summary>The item is a primary key index</summary>
            Index=4
        }
        
        /// <summary>The target type</summary>
        public enumTargetType TargetType = enumTargetType.None;
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new serializable target
        /// </summary>
        /// <param name="TargetType">The type of target</param>
        public MM_Serializable_Target(enumTargetType TargetType)
        {
            this.TargetType = TargetType;
        }
        #endregion

        #region Target checking
        /// <summary>
        /// Determine whether the member is for an element
        /// </summary>
        public bool IsElement
        {
            get { return (TargetType & enumTargetType.ElementCollection) == enumTargetType.ElementCollection; }
        }

        /// <summary>
        /// Determine whether the member is for the specific type
        /// </summary>
        public bool IsTypeSpecific
        {
            get { return (TargetType & enumTargetType.TypeCollection) == enumTargetType.TypeCollection; }
        }

        /// <summary>
        /// Determine whether the member is our primary key
        /// </summary>
        public bool IsIndex
        {
            get { return (TargetType &  enumTargetType.Index) == enumTargetType.Index; }
        }
        #endregion
    }
    #endregion

    /// <summary>
    /// This class offers the interface to saving and loading an element's XML.
    /// </summary>
    public class MM_Serializable
    {

        /// <summary>
        /// Report the current target type
        /// </summary>
        public MM_Serializable_Target TargetType
        {
            get
            {
                foreach (object obj in this.GetType().GetCustomAttributes(true))
                    if (obj is MM_Serializable_Target)
                        return (obj as MM_Serializable_Target);
                return null;
            }
        }       

        /// <summary>
        /// Create a new serializable element
        /// </summary>
        public MM_Serializable()
        { }

        /// <summary>
        /// Create a new serializable element
        /// </summary>
        /// <param name="ElementSource">The element source for the data</param>
        public MM_Serializable(XmlElement ElementSource)
        {
            ReadXml(ElementSource);
        }


        /// <summary>
        /// Create a new serializable element
        /// </summary>
        /// <param name="ElementSource">The element source for the data</param>
        /// <param name="Prefix"></param>
        public MM_Serializable(XmlElement ElementSource, String Prefix)
        {
            ReadXml(ElementSource, Prefix);
        }



        /// <summary>
        /// Create a new serializable element
        /// </summary>
        /// <param name="DataReader">The element source for the data</param>
        public MM_Serializable(DbDataReader DataReader)
        {
            for (int a = 0; a < DataReader.FieldCount; a++)
            {
                MemberInfo[] mIs = this.GetType().GetMember(DataReader.GetName(a), BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
                if (mIs.Length == 0)
                    Console.WriteLine("Unable to locate " + DataReader.GetName(a) + " for " + this.GetType().Name);
                else
                {
                    MemberInfo mI = mIs[0];
                    if (mI is FieldInfo)
                        (mI as FieldInfo).SetValue(this, RetrieveConvertedValue((mI as FieldInfo).FieldType, DataReader[a]));
                    else if (mI is PropertyInfo)
                        (mI as PropertyInfo).SetValue(this, RetrieveConvertedValue((mI as PropertyInfo).PropertyType, DataReader[a]), null);
                }
            }
            /*
            //Go field by field, and update our data
            FieldInfo fI = null;
            PropertyInfo pI = null;
            for (int a = 0; a < DataReader.FieldCount; a++)
            {
                if ((fI = this.GetType().GetField(DataReader.GetName(a), BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)) != null)
                    AssignValue(fI, RetrieveConvertedValue(fI.FieldType, DataReader[a].ToString()), this);
                else if ((pI = this.GetType().GetProperty(DataReader.GetName(a), BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)) != null)
                    AssignValue(pI, RetrieveConvertedValue(pI.PropertyType, DataReader[a]), this);
                else
                    MM_Log.LogEvent(new MM_Event_MemberNotFound(DataReader.GetName(a), this));

            }
            */
        }

        private class ObjectComparer : IComparer<Object>
        {
            #region IComparer<object> Members

            /// <summary>
            /// Compare two objects, to ensure they match up.
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(object x, object y)
            {
                bool IsLastX = false, IsLastY = false;
                if (x is FieldInfo)
                    IsLastX = (x as FieldInfo).FieldType == typeof(System.Windows.Forms.Control) || (x as FieldInfo).FieldType ==  typeof(MM_Display_Parameter);
                else
                    IsLastX = (x as PropertyInfo).PropertyType == typeof(System.Windows.Forms.Control) || (x as PropertyInfo).PropertyType == typeof(MM_Display_Parameter);

                if (y is FieldInfo)
                    IsLastY = (y as FieldInfo).FieldType == typeof(System.Windows.Forms.Control) || (y as FieldInfo).FieldType == typeof(MM_Display_Parameter);
                else
                    IsLastY = (y as PropertyInfo).PropertyType == typeof(System.Windows.Forms.Control) || (y as PropertyInfo).PropertyType == typeof(MM_Display_Parameter);


                if (IsLastX && !IsLastY)
                    return 1;
                else if (IsLastY && !IsLastX)
                    return -1;
                else
                    return String.Compare(x.GetType().GetProperty("Name").GetValue(x, null) as String, y.GetType().GetProperty("Name").GetValue(y,null) as String, true);                
            }

            #endregion
        }

        

        /// <summary>
        /// Write the serialized Xml for a specified object
        /// </summary>
        /// <param name="xW">The outgoing text writer</param>
        /// <param name="obj">The object to be serialized</param>
        public static void WriteXml(XmlTextWriter xW, Object obj)
        {
            if (obj is MM_Event)
                xW.WriteStartElement("Event");
            else if (obj is MM_Element && (obj as MM_Element).ElemType != null)
                xW.WriteStartElement((obj as MM_Element).ElemType.Name);
            else
                xW.WriteStartElement(obj.GetType().Name);

            WriteAttributes(xW, obj, "");
            xW.WriteEndElement();
        }

        /// <summary>
        /// Write out XML attributes with the specified prefix out
        /// </summary>
        /// <param name="xW"></param>
        /// <param name="obj"></param>
        /// <param name="Prefix"></param>
        public static void WriteAttributes(XmlTextWriter xW, Object obj, String Prefix)
        {
            SortedDictionary<String, Object> ExportObjects = new SortedDictionary<String, object>();
            if (obj == null)
                return;

            foreach (FieldInfo fI in obj.GetType().GetFields())
            {
                MM_Serializable_Target tVal = null;
                foreach (Object obj2 in fI.GetCustomAttributes(true))
                    if (obj2 is MM_Serializable_Target)
                        tVal = obj2 as MM_Serializable_Target;

                Object InValue = fI.GetValue(obj);
                if (tVal == null || tVal.TargetType != MM_Serializable_Target.enumTargetType.None)
                    if (InValue is IDictionary && ((InValue as IDictionary).Count > 0))
                        ExportObjects.Add(fI.Name, InValue);
                    else if (InValue is IList && (InValue as IList).Count > 0)
                        ExportObjects.Add(fI.Name, InValue);
                    else if (InValue != null && !ExportObjects.ContainsKey(fI.Name))
                        ExportObjects.Add(fI.Name, InValue);
            }

            foreach (PropertyInfo pI in obj.GetType().GetProperties())
            {
                MM_Serializable_Target tVal = null;
                foreach (Object obj2 in pI.GetCustomAttributes(true))
                    if (obj2 is MM_Serializable_Target)
                        tVal = obj2 as MM_Serializable_Target;

                Object InValue = pI.GetValue(obj, null);
                if (tVal == null || tVal.TargetType != MM_Serializable_Target.enumTargetType.None)
                    if (InValue is IDictionary && ((InValue as IDictionary).Count > 0))
                        ExportObjects.Add(pI.Name, InValue);
                    else if (InValue is IList && (InValue as IList).Count > 0)
                        ExportObjects.Add(pI.Name, InValue);
                    else if (InValue != null && !ExportObjects.ContainsKey(pI.Name))
                        ExportObjects.Add(pI.Name, InValue);
            }

            //Set up our prefix
            if (String.IsNullOrEmpty(Prefix))
                Prefix = "";
            else
                Prefix += ".";


            //First, export the ElemType value if we have it
            foreach (string str in "ElemType,TEID".Split(','))
            {
                if (ExportObjects.ContainsKey(str))
                    WriteXMLData(Prefix + str, ExportObjects[str], xW);
                ExportObjects.Remove(str);
            }

            //Now, export all objects.
            foreach (KeyValuePair<String, Object> kvp in ExportObjects)
                WriteXMLData(Prefix + kvp.Key, kvp.Value, xW);            
        }

        /// <summary>
        /// Write the boundary information to the XML Text writer
        /// </summary>
        /// <param name="xW">The outgoing text writer</param>
        public void WriteXML(XmlTextWriter xW)
        {
            WriteXml(xW, this);            
        }

        /// <summary>
        /// Write this object to a database
        /// </summary>
        /// <param name="dbConn"></param>
        /// <param name="dTrans"></param>
        /// <param name="TableName"></param>
        public void WriteDatabase(DbConnection dbConn, DbTransaction dTrans, String TableName)
        {
            //Create our dictionary with values
            Dictionary<String, Object> Parameters = new Dictionary<string, object>();
            KeyValuePair<String, Object> Index=new KeyValuePair<string,object>(null,null);
            foreach (MemberInfo mVal in this.GetType().GetMembers())
            {
                Object OutVal = null;
                if (mVal is FieldInfo)
                    OutVal = (mVal as FieldInfo).GetValue(this);
                else if (mVal is PropertyInfo)
                    OutVal = (mVal as PropertyInfo).GetValue(this, null);

                MM_Serializable_Target tVal = null;
                foreach (Object obj in mVal.GetCustomAttributes(true))
                    if (obj is MM_Serializable_Target)
                        tVal = obj as MM_Serializable_Target;
                if (tVal == null)
                { }
                else if (tVal.IsIndex)
                    Index = new KeyValuePair<string, object>(mVal.Name, OutVal);
                else if (tVal.IsTypeSpecific)
                    Parameters.Add(mVal.Name, OutVal);
            }

            WriteDatabase(TableName, Parameters, Index, dbConn, dTrans);
            
        }


        /// <summary>
        /// Write data out to the database
        /// </summary>
        /// <param name="TableName">The table name</param>
        /// <param name="Parameters"></param>
        /// <param name="Index"></param>
        /// <param name="dConn"></param>
        /// <param name="dTrans"></param>
        private void WriteDatabase(String TableName, Dictionary<String, Object> Parameters, KeyValuePair<String, Object> Index, DbConnection dConn, DbTransaction dTrans)
        {

            //First, build an insert function
            StringBuilder sB = new StringBuilder();
            bool FirstKey = true;
            foreach (KeyValuePair<String, Object> kvp in Parameters)
            {
                sB.Append((FirstKey ? "INSERT INTO " + TableName + "([" : ", [") + kvp.Key + "]");
                FirstKey = false;
            }

            bool UpdateIndex = false;
            if (Index.Value == null)
                sB.Append(") values ");
            else if (Index.Value.Equals(-1))
            {
                sB.Append(") values ");
                UpdateIndex = true;
            }
            else
                sB.Append(", [" + Index.Key + "]) values ");


            
            FirstKey = true;
            foreach (KeyValuePair<String, Object> kvp in Parameters)
            {
                sB.Append((FirstKey ? "(:" : ", :") + kvp.Key);
                FirstKey = false;
            }

            if (UpdateIndex)
                sB.Append("); SELECT last_insert_rowid() AS [UpdatedIndex]");
            else if (Index.Value == null)
                sB.Append(")");
            else
                sB.Append(", :" + Index.Key + ")");
            

            //Prepare to execute our insert function
            DbCommand dCmd = dConn.CreateCommand();
            dCmd.CommandText = sB.ToString();
            dCmd.Transaction = dTrans;
            dCmd.CommandType = System.Data.CommandType.Text;
            dCmd.Prepare();
            
            foreach (KeyValuePair<String, Object> kvp in Parameters)
            {
                Object inValue = ConvertValue(kvp.Value);
                if (inValue is byte[])
                {
                    DbParameter dParam = dCmd.CreateParameter();
                    dParam.ParameterName = kvp.Key;
                    dParam.DbType = System.Data.DbType.Binary;
                    dParam.Direction = System.Data.ParameterDirection.Input;
                    dParam.Value = inValue;
                    dParam.Size = ((Byte[])inValue).Length;
                    dCmd.Parameters.Add(dParam);
                }
                else
                {
                    DbParameter dParam = dCmd.CreateParameter();
                    dParam.ParameterName = kvp.Key;
                    dParam.Value = inValue;
                    dCmd.Parameters.Add(dParam);
                }
            }


            if (!UpdateIndex && Index.Value != null)
            {
                DbParameter dParam = dCmd.CreateParameter();
                dParam.ParameterName = Index.Key;
                dParam.Value = ConvertValue(Index.Value);
                dCmd.Parameters.Add(dParam);
            }                



            //Attempt to execute the insert
            try
            {
                if (UpdateIndex)
                {
                    MemberInfo mI = this.GetType().GetMember(Index.Key)[0];
                    if (mI is FieldInfo)
                        (mI as FieldInfo).SetValue(Convert.ChangeType(dCmd.ExecuteScalar(), (mI as FieldInfo).FieldType), this);
                    else if (mI is PropertyInfo)
                        (mI as PropertyInfo).SetValue(Convert.ChangeType(dCmd.ExecuteScalar(), (mI as PropertyInfo).PropertyType), this, null);
                }
                else
                    using (DbDataReader dRd = dCmd.ExecuteReader())
                        dRd.Close();
            }
            catch (Exception ex)
            {                
                if (ex is DbException)
                {
                    //If we weren't able to insert due to a duplicate record, change the statement to an update.
                    sB.Remove(0, sB.Length);
                    FirstKey = true;
                    foreach (KeyValuePair<String, Object> kvp in Parameters)
                    {
                        sB.Append((FirstKey ? "   UPDATE " + TableName + " set [" : ", [") + kvp.Key + "]=:" + kvp.Key);
                        FirstKey = false;
                    }
                    sB.Append(" where " + TableName + ".[" + Index.Key + "]=:" + Index.Key);

                    try
                    {
                        dCmd.CommandText = sB.ToString();
                        using (DbDataReader dRd = dCmd.ExecuteReader())
                            dRd.Close();
                    }
                    catch (Exception ex2)
                    {
                        Console.WriteLine("Error in row update: " + ex2.Message);
                    }
                }
                else
                    Console.WriteLine("Error in row insert: " + ex.Message);


            }
            dCmd.Dispose();
        }

        /// <summary>
        /// Go through all attributes and sub-elements within this element, and load in the values
        /// </summary>
        /// <param name="XmlToRead">The Xml Element to be read</param>        
        public void ReadXml(XmlElement XmlToRead)
        {
            foreach (XmlAttribute xAttr in XmlToRead.Attributes)
                AssignValue(xAttr.Name, xAttr.Value, this);
        }

        /// <summary>
        /// Go through all attributes and sub-elements within this element, and load in the values
        /// </summary>
        /// <param name="XmlToRead">The Xml Element to be read</param>        
        /// <param name="Prefix"></param>
        public void ReadXml(XmlElement XmlToRead, String Prefix)
        {
            foreach (XmlAttribute xAttr in XmlToRead.Attributes)
                if (xAttr.Name.StartsWith(Prefix + "."))
                    AssignValue(xAttr.Name.Substring(Prefix.Length+1), xAttr.Value, this);
        }


        
        /// <summary>
        /// Go through all attributes and sub-elements within the XML, and load in the values into the specified static class
        /// </summary>
        /// <param name="XmlToRead">The XML to be read</param>
        /// <param name="Target">The item to receive the values</param>
        public static void ReadXml(XmlElement XmlToRead, Object Target)
        {
            Type TargetType = (Target is Type ? Target as Type : Target.GetType());
            foreach (XmlAttribute xAttr in XmlToRead.Attributes)
                if (xAttr.Name.IndexOf('.') != -1)
                {
                    FieldInfo fI =  TargetType.GetField(xAttr.Name.Split('.')[0]);
                    PropertyInfo pI = TargetType.GetProperty(xAttr.Name.Split('.')[0]);
                    String AttrValue = xAttr.Name.Split('.')[1];
                    MM_Element ExistingElement=null;
                   
                        if (fI != null)
                            ExistingElement = fI.GetValue(Target) as MM_Element;
                        else if (pI != null)
                            ExistingElement = pI.GetValue(Target, null) as MM_Element;
                    

                    if (fI != null && AttrValue == "ElemType")
                        fI.SetValue(Target, ExistingElement = MM_Element.CreateElement(MM_Overall_Display.FindElementType(xAttr.Value)));
                    else if (pI != null && AttrValue == "ElemType")
                        pI.SetValue(Target, ExistingElement = MM_Element.CreateElement(MM_Overall_Display.FindElementType(xAttr.Value)), null);
                    else if (AttrValue == "TEID")
                    {
                        UInt64 TEID = Convert.ToUInt64(xAttr.Value);
                        if (MM_Repository.TEIDs.ContainsKey(TEID) && MM_Repository.TEIDs[TEID].ElemType == ExistingElement.ElemType)
                            if (fI != null)
                                fI.SetValue(Target, MM_Repository.TEIDs[TEID]);
                            else
                                pI.SetValue(Target, MM_Repository.TEIDs[TEID], null);
                        else
                        {
                            bool FoundIt = false;
                            foreach (MM_Database Db in MM_Repository.Databases)
                            {
                                MM_Element FoundElement = Db.LocateElement(TEID);
                                if (FoundElement != null)
                                {
                                    FoundIt = true;
                                    if (fI != null)
                                        fI.SetValue(Target, FoundElement);
                                    else
                                        pI.SetValue(Target, FoundElement, null);
                                }
                            }
                            if (!FoundIt)
                                ExistingElement.TEID = TEID;
                        }
                    }
                    else if (!MM_Repository.TEIDs.ContainsKey(ExistingElement.TEID) || MM_Repository.TEIDs[ExistingElement.TEID] != ExistingElement)
                        AssignValue(AttrValue, xAttr.Value, ExistingElement);                                                                  
                }
                else
                {
                    FieldInfo fI = TargetType.GetField(xAttr.Name);
                    PropertyInfo pI = TargetType.GetProperty(xAttr.Name);
                    if (fI != null)
                        ConvertAndStoreValue(fI, fI.FieldType, xAttr.Value, Target);
                    else if (pI != null && pI.CanWrite)
                        ConvertAndStoreValue(pI, pI.PropertyType, xAttr.Value, Target);
                    else if (pI == null)
                        MM_Log.LogEvent(new MM_Event_MemberNotFound(xAttr.Name, Target));
                }
        }

        /// <summary>
        /// Assign a particular value to a field/property
        /// </summary>
        /// <param name="fpI">The field/property's information</param>
        /// <param name="OutgoingValue">The outgoing value</param>
        /// <param name="Target">The target receiving the new value</param>
        private static void AssignValue(Object fpI, Object OutgoingValue, Object Target)
        {
            if (fpI is FieldInfo)
                (fpI as FieldInfo).SetValue(Target, OutgoingValue);
            else if (fpI is PropertyInfo && (fpI as PropertyInfo).CanWrite)
                (fpI as PropertyInfo).SetValue(Target, OutgoingValue, null);
        }

        private static void AssignValue(String PropertyName, String PropertyValue, Object Target)
        {
            FieldInfo fI = Target.GetType().GetField(PropertyName, BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
            FieldInfo fI2 = Target.GetType().GetField("_" + PropertyName, BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
            PropertyInfo pI = Target.GetType().GetProperty(PropertyName, BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
            if (fI != null)
                ConvertAndStoreValue(fI, fI.FieldType, PropertyValue, Target);
            else if (fI2 != null)
                ConvertAndStoreValue(fI2, fI2.FieldType, PropertyValue, Target);
            else if (pI != null && pI.CanWrite)
                ConvertAndStoreValue(pI, pI.PropertyType, PropertyValue, Target);
            else if (pI == null)
                MM_Log.LogEvent(new MM_Event_MemberNotFound(PropertyName, Target));                
        }

        /// <summary>
        /// Retrieve all members for an element, ensuring the top level ones are handled.
        /// </summary>
        /// <param name="InElem"></param>
        /// <returns></returns>
        public static MemberInfo[] GetMembers(Object InElem)
        {
            SortedDictionary<String, MemberInfo> OutMember = new SortedDictionary<string, MemberInfo>(StringComparer.CurrentCultureIgnoreCase);
            foreach (MemberInfo mI in InElem.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty))
                if (mI is FieldInfo || mI is PropertyInfo)
                    if (OutMember.ContainsKey(mI.Name))
                        Console.WriteLine("?");
                    else
                        OutMember.Add(mI.Name, mI);

            //Now, pull in the remaining elements
            foreach (MemberInfo mI in InElem.GetType().GetMembers())
                if ((mI is FieldInfo || mI is PropertyInfo) && !OutMember.ContainsKey(mI.Name))
                    OutMember.Add(mI.Name, mI);

            MemberInfo[] OutMembers = new MemberInfo[OutMember.Count];
            OutMember.Values.CopyTo(OutMembers, 0);
            return OutMembers;
        }

        /// <summary>
        /// Convert a value to the appropriate output for SQL
        /// </summary>
        /// <param name="inValue"></param>
        /// <returns></returns>
        public static Object ConvertValue(Object inValue)
        {
            //If we have an index, return it
            if (inValue == null)
                return DBNull.Value;
            else if (inValue is float && float.IsNaN((float)inValue))
                return DBNull.Value;
            else if (inValue.GetType().GetMember("Index").Length > 0)
            {
                MemberInfo mI = inValue.GetType().GetMember("Index")[0];
                if (mI is FieldInfo)
                    return (mI as FieldInfo).GetValue(inValue);
                else
                    return (mI as PropertyInfo).GetValue(inValue, null);
            }
            //If we have a TEID, return it.
            else if (inValue is MM_Element)
                return (inValue as MM_Element).TEID;
                else if (inValue is Dictionary<String,String>)
            {
                StringBuilder sB = new StringBuilder();
                foreach (KeyValuePair<String,String> kvp in (inValue as Dictionary<String,String>))
                    sB.AppendLine(kvp.Key + "=" + kvp.Value);                    
                return sB.ToString();
            }
            else if (inValue is IEnumerable<MM_Element>)
            {
                StringBuilder sB = new StringBuilder();
                foreach (MM_Element Elem in (inValue as IEnumerable<MM_Element>))
                    sB.Append(sB.Length == 0 ? Elem.TEID.ToString() : "," + Elem.TEID.ToString());
                return sB.ToString();
            }
            else if (inValue is IEnumerable<MM_KVLevel>)
            {
                int OutResult = 0;
                foreach (MM_KVLevel KVLevel in (inValue as IEnumerable<MM_KVLevel>))
                    OutResult += KVLevel.Index;
                return OutResult;
            }
            else if (inValue is IEnumerable<MM_Element_Type>)
            {
                Char[] OutResult = new string('0', MM_Overall_Display.ElemTypes.Count + 1).ToCharArray();
                foreach (MM_Element_Type ElemType in (inValue as IEnumerable<MM_Element_Type>))
                    OutResult[ElemType.Index] = '1';
                return new String(OutResult);
            }
            else if (inValue is IEnumerable<PointF>)
            {
                using (MemoryStream OutStream = new MemoryStream())
                {
                    foreach (PointF pt in (inValue as IEnumerable<PointF>))
                    {
                        OutStream.Write(BitConverter.GetBytes(pt.X), 0, 4);
                        OutStream.Write(BitConverter.GetBytes(pt.Y), 0, 4);
                    }
                    return OutStream.ToArray();
                }
            }

            else
                return inValue;
        }

        /// <summary>
        /// Convert a value into a specified type
        /// </summary>
        /// <param name="OutgoingType">The outgoing value's type</param>
        /// <param name="OutgoingValue">The value in string form</param>
        public static Object RetrieveConvertedValue(Type OutgoingType, Object OutgoingValue)
        {
            //Start checking whether our type is an array or list, and handle accordingly.
            if (OutgoingValue is DBNull)
                return null;
            else if (OutgoingType == typeof(List<MM_KVLevel>))
            {
                List<MM_KVLevel> OutList = new List<MM_KVLevel>();
                int Index;
                if (OutgoingValue is String)
                {
                    foreach (String CurLevel in OutgoingValue.ToString().Split(','))
                        if (MM_Overall_Display.KVLevels.ContainsKey(CurLevel))
                            OutList.Add(MM_Overall_Display.KVLevels[CurLevel]);
                        else if (int.TryParse(CurLevel, out Index))
                            foreach (MM_KVLevel KVLevel in MM_Overall_Display.KVLevels.Values)
                                if (Index == KVLevel.Index)
                                    OutList.Add(KVLevel);
                }
                else
                    foreach (MM_KVLevel KVLevel in MM_Overall_Display.KVLevels.Values)
                        if ((KVLevel.Index & Convert.ToInt32(OutgoingValue)) == KVLevel.Index)
                            OutList.Add(KVLevel);
                OutList.TrimExcess();
                return OutList;
            }
            else if (OutgoingType == typeof(List<MM_Element_Type>))
            {
                String OutgoingString = (string)OutgoingValue;
                List<MM_Element_Type> ElemTypes = new List<MM_Element_Type>();
                foreach (MM_Element_Type ElemType in MM_Overall_Display.ElemTypes.Values)
                    if (ElemType.Index < OutgoingString.Length && OutgoingString[ElemType.Index] == '1')
                        ElemTypes.Add(ElemType);
                ElemTypes.TrimExcess();
                return ElemTypes;
            }
            else if (OutgoingType.Name == "List`1" && OutgoingValue is String)
            {
                String[] splStr = (OutgoingValue as String).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                IList OutList = Activator.CreateInstance(OutgoingType, (Object)splStr.Length) as IList;
                foreach (String OutPiece in splStr)
                    OutList.Add(RetrieveConvertedValue(OutgoingType.GetGenericArguments()[0], OutPiece));
                return OutList;
            }
            //If we're pulling in node/bus connectivity, return nothing - this will be handled in the initiator.
            else if (OutgoingType == typeof(Dictionary<MM_OneLine_Element, MM_OneLine_Node>))
                return null;
            else if (OutgoingType.Name == "Dictionary`2" && OutgoingValue is String)
            {
                String[] splStr = (OutgoingValue as String).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                IDictionary OutDictionary = Activator.CreateInstance(OutgoingType, (Object)(splStr.Length / 2)) as IDictionary;
                Type[] OutTypes = OutgoingType.GetGenericArguments();
                for (int a = 0; a < splStr.Length; a += 2)
                {
                    Object NewKey = RetrieveConvertedValue(OutTypes[0], splStr[a]);
                    Object NewValue = RetrieveConvertedValue(OutTypes[1], splStr[a + 1]);
                    OutDictionary.Add(NewKey, NewValue);
                }
                return OutDictionary;
            }
            else if (OutgoingType == typeof(Color) && OutgoingValue is String)
                return ColorTranslator.FromHtml((String)OutgoingValue);
            else if (OutgoingType == typeof(Pen) && OutgoingValue is String)
            {
                String[] splStr = (OutgoingValue as string).Split(',');
                return new Pen(ColorTranslator.FromHtml(splStr[0]), float.Parse(splStr[1]));
            }
            else if (OutgoingType == typeof(Color))
                return Color.FromArgb(Convert.ToInt32(OutgoingValue));
            else if (OutgoingType.IsEnum && OutgoingValue is String)
                if (Array.IndexOf(Enum.GetNames(OutgoingType), (string)OutgoingValue) != -1)
                    return Enum.Parse(OutgoingType, (string)OutgoingValue);
                else
                {
                    foreach (String TypeToTest in Enum.GetNames(OutgoingType))
                        if (TypeToTest != "Unknown" && TypeToTest.StartsWith((string)OutgoingValue))
                            return Enum.Parse(OutgoingType, TypeToTest);
                    return Enum.Parse(OutgoingType, "Unknown");
                }
            else if (OutgoingType.IsEnum && (OutgoingValue is int || OutgoingValue is long))
                return Enum.GetValues(OutgoingType).GetValue(Convert.ToInt32(OutgoingValue));
            else if (OutgoingType == typeof(PointF))
                return new MM_PointF_Converter().ConvertFrom(OutgoingValue);
            else if (OutgoingType == typeof(MM_KVLevel) && OutgoingValue is string)
            {
                MM_KVLevel OutLevel;
                if (!MM_Overall_Display.KVLevels.TryGetValue((string)OutgoingValue, out OutLevel))
                    MM_Overall_Display.KVLevels.Add((string)OutgoingValue, new MM_KVLevel((string)OutgoingValue, "Green"));
                return OutLevel;
            }
            else if (OutgoingType == typeof(MM_KVLevel) && (OutgoingValue is int || OutgoingValue is Decimal))
            {
                foreach (MM_KVLevel KVLevel in MM_Overall_Display.KVLevels.Values)
                    if (KVLevel.Index == Convert.ToInt32(OutgoingValue))
                        return KVLevel;
                throw new InvalidOperationException("Unable to locate KV level " + (int)OutgoingValue);
            }
            else if (OutgoingType == typeof(MM_Boundary) && OutgoingValue is String)
                return MM_Repository.Counties[(String)OutgoingValue];
            else if (OutgoingType == typeof(MM_Boundary) && OutgoingValue is Decimal)
                return MM_Repository.Counties[Convert.ToInt32(OutgoingValue)];

            else if (OutgoingType == typeof(MM_Event) && (OutgoingValue is String || OutgoingValue is UInt64))
                return MM_Repository.Events[Convert.ToUInt64(OutgoingValue)];
            else if (OutgoingType == typeof(MM_Zone) && (OutgoingValue is String || OutgoingValue is UInt64))
                return MM_Repository.Zones[Convert.ToInt32(OutgoingValue)];
            else if ((OutgoingType == typeof(MM_Element) || OutgoingType.BaseType == typeof(MM_Element)) && (OutgoingValue is String || OutgoingValue is UInt64))
                if (MM_Repository.TEIDs.ContainsKey(Convert.ToUInt64(OutgoingValue)))
                    return MM_Repository.TEIDs[Convert.ToUInt64(OutgoingValue)];
                else
                    return null;
            else if (OutgoingType == typeof(MM_Generation_Type) && OutgoingValue is String)
                return MM_Overall_Display.GenerationTypes[(String)OutgoingValue];
            else if (OutgoingType == typeof(MM_Element_Type) && OutgoingValue is String)
                return MM_Overall_Display.FindElementType((string)OutgoingValue);
            else if (OutgoingType == typeof(MM_Zone))
                return MM_Repository.Zones[Convert.ToInt32(OutgoingValue)];
            else if (OutgoingType == typeof(Bitmap) && OutgoingValue is byte[])
                return Bitmap.FromStream(new MemoryStream((byte[])OutgoingValue));
            else if (OutgoingType == typeof(Bitmap) && OutgoingValue is String)
                return Bitmap.FromStream(new MemoryStream(Convert.FromBase64String((string)OutgoingValue)));
            else if (OutgoingType == typeof(Bitmap))
                return null;
            else if (OutgoingType.Name == "MM_Contingency_Grouping")
                return null;
            else if (OutgoingType.Name == "CIM_Element")
                return null;
            else if (OutgoingType == typeof(Rectangle))
            {
                String[] splStr = ((string)OutgoingValue).Split(',');
                return new Rectangle(int.Parse(splStr[0]), int.Parse(splStr[1]), int.Parse(splStr[2]), int.Parse(splStr[3]));
            }
            else if (OutgoingType == typeof(Point))
            {
                String[] splStr = ((string)OutgoingValue).Split(',');
                return new Point(int.Parse(splStr[0]), int.Parse(splStr[1]));
            }
            else if (OutgoingType == typeof(Point[]))
            {
                String[] splStr = ((string)OutgoingValue).Split(',');
                Point[] OutPoint = new Point[splStr.Length / 2];
                for (int a = 0; a < splStr.Length; a += 2)
                    OutPoint[a / 2] = new Point(int.Parse(splStr[a]), int.Parse(splStr[a + 1]));
                return OutPoint;
            }
            else if (OutgoingType == typeof(UInt64[]))
            {
                String[] splStr = ((string)OutgoingValue).Split(',');
                UInt64[] outVal = new ulong[splStr.Length];
                for (int a = 0; a < splStr.Length; a++)
                    outVal[a] = Convert.ToUInt64(splStr[a]);
                return outVal;
            }
            else if (OutgoingType == typeof(Type))
                return Type.GetType("System." + (string)OutgoingValue);
            else if (OutgoingType == typeof(Font))
            {
                TypeConverter tc = TypeDescriptor.GetConverter(typeof(Font));
                return (Font)tc.ConvertFromString((string)OutgoingValue);
            }
            else if (OutgoingType.IsArray)
            {
                string[] splStr = ((string)OutgoingValue).Split(',');
                Array OutArray = Array.CreateInstance(OutgoingType.GetElementType(), splStr.Length);
                for (int a = 0; a < splStr.Length; a++)
                    OutArray.SetValue(RetrieveConvertedValue(OutgoingType.GetElementType(), splStr[a]), a);

                return OutArray;
            }
            else if (OutgoingType == typeof(MM_rdfID))
                return new MM_rdfID((string)OutgoingValue);
            else if (OutgoingType == typeof(MM_Element_Type))
                return MM_Overall_Display.ElemTypes[Convert.ToInt32(OutgoingValue)];
            else if (OutgoingType == typeof(MM_Element) || OutgoingType.BaseType == typeof(MM_Element))
            {
                MM_Element OutElement;
                UInt64 TEID = 0;
                if (OutgoingValue is String && !UInt64.TryParse((string)OutgoingValue, out TEID))
                    return null;
                else if (OutgoingValue is String == false)
                    TEID = Convert.ToUInt64(OutgoingValue);

                if (MM_Repository.TEIDs.TryGetValue(TEID, out OutElement))
                    return OutElement;
                else
                    foreach (MM_Database Db in MM_Repository.Databases)
                        if ((OutElement = Db.LocateElement(TEID)) != null)
                            return OutElement;
                return OutElement;
            }
            else
                return Convert.ChangeType(OutgoingValue, OutgoingType);
            
        }


        /// <summary>
        /// Convert and store a value from XML into its appropriate format
        /// </summary>
        /// <param name="fpI">The field or property info</param>
        /// <param name="OutgoingType">The outgoing type of the variable</param>
        /// <param name="OutgoingValue">The outgoing value (in string format)</param>        
        /// <param name="Target">The target receiving the new value</param>
        private static void ConvertAndStoreValue(Object fpI, Type OutgoingType, String OutgoingValue, Object Target)
        {
            AssignValue(fpI, RetrieveConvertedValue(OutgoingType, OutgoingValue), Target);
        }

        /*   
           else if (OutgoingType == typeof(Single[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               Single[] OutPts = new Single[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutPts[a] = MM_Repository.ToSingle(splStr[a]);
               AssignValue(fpI, OutPts, Target);
           }
           else if (OutgoingType == typeof(PointF[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               PointF[] OutPts = new PointF[splStr.Length / 2];
               for (int a = 0; a < splStr.Length; a += 2)
                   OutPts[a / 2] = new PointF(MM_Repository.ToSingle(splStr[a]), MM_Repository.ToSingle(splStr[a + 1]));
               AssignValue(fpI, OutPts, Target);
           }
           else if (OutgoingType == typeof(List<PointF>))
           {
               String[] splStr = OutgoingValue.Split(',');
               List<PointF> OutStr = new List<PointF>(splStr.Length / 2);
               for (int a = 0; a < splStr.Length; a += 2)
                   OutStr.Add(new PointF(MM_Repository.ToSingle(splStr[a]), MM_Repository.ToSingle(splStr[a + 1])));
               AssignValue(fpI, OutStr, Target);
           }
           else if (OutgoingType == typeof(List<MM_Weather_Station>))
           {
               String[] splStr = OutgoingValue.Split(',');
               List<MM_Weather_Station> OutStr = new List<MM_Weather_Station>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutStr.Add(MM_Repository.Weather.WeatherStations[splStr[a]]);
               AssignValue(fpI, OutStr, Target);
           }
           else if (OutgoingType == typeof(Dictionary<UInt64, MM_AlarmEvent>))
           {
               String[] splStr = OutgoingValue.Split(',');
               Dictionary<UInt64, MM_AlarmEvent> OutDic = new Dictionary<ulong, MM_AlarmEvent>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutDic.Add(UInt64.Parse(splStr[a]), MM_Repository.LocateEvent(UInt64.Parse(splStr[a])));
               AssignValue(fpI, OutDic, Target);
           }
           else if (OutgoingType == typeof(Dictionary<UInt64, MM_Element>))
           {
               String[] splStr = OutgoingValue.Split(',');
               Dictionary<UInt64, MM_Element> OutDic = new Dictionary<ulong, MM_Element>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutDic.Add(UInt64.Parse(splStr[a]), MM_Repository.LocateElement(UInt64.Parse(splStr[a])));
               AssignValue(fpI, OutDic, Target);
           }
           else if (OutgoingType == typeof(List<MM_KVLevel>))
           {
               String[] splStr = OutgoingValue.Split(',');
               List<MM_KVLevel> OutLevels = new List<MM_KVLevel>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutLevels.Add(MM_Overall_Display.KVLevels[splStr[a]]);
               AssignValue(fpI, OutLevels, Target);
           }
           else if (OutgoingType == typeof(MM_KVLevel[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_KVLevel[] OutLevels = new MM_KVLevel[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutLevels[a] = MM_Overall_Display.KVLevels[splStr[a]];
               AssignValue(fpI, OutLevels, Target);
           }
           else if (OutgoingType == typeof(List<MM_Substation>))
           {
               String[] splStr = OutgoingValue.Split(',');
               List<MM_Substation> OutSubs = new List<MM_Substation>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutSubs.Add(MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Substation)) as MM_Substation);
               AssignValue(fpI, OutSubs, Target);
           }
           else if (OutgoingType == typeof(MM_Substation[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_Substation[] OutSubs = new MM_Substation[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutSubs[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Substation)) as MM_Substation;
               AssignValue(fpI, OutSubs, Target);
           }
           else if (OutgoingType == typeof(List<MM_Element_Type>))
           {
               String[] splStr = OutgoingValue.Split(',');
               List<MM_Element_Type> OutElems = new List<MM_Element_Type>(splStr.Length);
               for (int a = 0; a < splStr.Length; a++)
                   OutElems.Add(MM_Overall_Display.ElemTypes[splStr[a]]);
               AssignValue(fpI, OutElems, Target);
           }
           else if (OutgoingType == typeof(MM_Load[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_Load[] OutLoads = new MM_Load[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutLoads[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Load)) as MM_Load;
               AssignValue(fpI, OutLoads, Target);
           }
           else if (OutgoingType == typeof(MM_Unit[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_Unit[] OutUnits = new MM_Unit[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutUnits[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Unit)) as MM_Unit;
               AssignValue(fpI, OutUnits, Target);
           }
           else if (OutgoingType == typeof(MM_Transformer[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_Transformer[] OutTransformers = new MM_Transformer[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutTransformers[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Transformer)) as MM_Transformer;
               AssignValue(fpI, OutTransformers, Target);
           }
           else if (OutgoingType == typeof(MM_Substation))
               AssignValue(fpI, MM_Repository.LocateElement(Convert.ToUInt64(OutgoingValue), typeof(MM_Substation)), Target);
           else if (OutgoingType == typeof(MM_Electrical_Bus[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_Electrical_Bus[] OutElectricalBus = new MM_Electrical_Bus[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutElectricalBus[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_Electrical_Bus)) as MM_Electrical_Bus;
               AssignValue(fpI, OutElectricalBus, Target);
           }
           else if (OutgoingType == typeof(MM_Contingency))
               AssignValue(fpI, MM_Repository.LocateElement(Convert.ToUInt64(OutgoingValue), typeof(MM_Contingency)), Target);
           else if (OutgoingType == typeof(MM_ShuntCompensator[]))
           {
               String[] splStr = OutgoingValue.Split(',');
               MM_ShuntCompensator[] OutSC = new MM_ShuntCompensator[splStr.Length];
               for (int a = 0; a < splStr.Length; a++)
                   OutSC[a] = MM_Repository.LocateElement(Convert.ToUInt64(splStr[a]), typeof(MM_ShuntCompensator)) as MM_ShuntCompensator;
               AssignValue(fpI, OutSC, Target);
           }
           else if (OutgoingType == typeof(MM_Element_Type))
               AssignValue(fpI, MM_Overall_Display.ElemTypes[OutgoingValue], Target);
           else if (OutgoingType == typeof(MM_Company))
               AssignValue(fpI, MM_Repository.LocateElement(Convert.ToUInt64(OutgoingValue), typeof(MM_Company)), Target);
           else if (OutgoingType == typeof(MM_AlarmEvent_Type))
               AssignValue(fpI, MM_Overall_Display.EventTypes[OutgoingValue], Target);
           else if (OutgoingType == typeof(DateTime))
               AssignValue(fpI, XmlConvert.ToDateTime(OutgoingValue, XmlDateTimeSerializationMode.Unspecified), Target);
           else if (OutgoingType == typeof(MM_Communication.ConnectionStateEnum))
               AssignValue(fpI, Enum.Parse(typeof(MM_Communication.ConnectionStateEnum), OutgoingValue), Target);
           else if (OutgoingType == typeof(System.Windows.Forms.Label))
           { }
           else if (OutgoingType == typeof(MM_Zone))
           {
               foreach (List<MM_Zone> ZoneToSearch in new List<MM_Zone>[] { MM_Repository.WeatherZones, MM_Repository.LoadZones })
                   foreach (MM_Zone Zone in ZoneToSearch)
                       if (Zone.Name == OutgoingValue)
                           AssignValue(fpI, Zone, Target);
           }
           else if (OutgoingType == typeof(MM_Substation_Display.SubstationViewEnum))
               AssignValue(fpI, Enum.Parse(typeof(MM_Substation_Display.SubstationViewEnum), OutgoingValue), Target);
           else if (OutgoingType == typeof(MM_Overall_Display.MM_Contour_Enum))
               AssignValue(fpI, Enum.Parse(typeof(MM_Overall_Display.MM_Contour_Enum), OutgoingValue), Target);
           else if (OutgoingType == typeof(MM_AlarmEvent_Type.DisplayModeEnum))
               AssignValue(fpI, Enum.Parse(typeof(MM_AlarmEvent_Type.DisplayModeEnum), OutgoingValue), Target);
           else if (fpI is FieldInfo)
               MM_Log.LogError("Unable to handle type " + (fpI as FieldInfo).FieldType.Name + " for " + (fpI as FieldInfo).Name,0,0);
           else if (fpI is PropertyInfo)
               MM_Log.LogError("Unable to handle type " + (fpI as PropertyInfo).PropertyType.Name + " for " + (fpI as PropertyInfo).Name,0,0);
       }
       */

        /// <summary>
        /// Write an XML snippet to the text writer
        /// </summary>
        /// <param name="Name">The name of the attribute</param>
        /// <param name="Value">The value of the attribute</param>
        /// <param name="xW">The output XML text writer</param>
        public static void WriteXMLData(String Name, Object Value, XmlTextWriter xW)
        {
            if (Value is PointF)
                xW.WriteAttributeString(Name, ((PointF)Value).X.ToString() + "," + ((PointF)Value).Y.ToString());
            else if (Value == null)
            { }
            else if (Value is MM_rdfID)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is Font)
            {
                TypeConverter tc = TypeDescriptor.GetConverter(typeof(Font));
                xW.WriteAttributeString(Name, tc.ConvertToString(Value));
            }
            else if (Value is RectangleF)
                xW.WriteAttributeString(Name, ((RectangleF)Value).Left.ToString() + "," + ((RectangleF)Value).Top.ToString() + "," + ((RectangleF)Value).Width.ToString() + "," + ((RectangleF)Value).Height.ToString() + ",");
            else if (Value is Rectangle)
                xW.WriteAttributeString(Name, ((Rectangle)Value).Left.ToString() + "," + ((Rectangle)Value).Top.ToString() + "," + ((Rectangle)Value).Width.ToString() + "," + ((Rectangle)Value).Height.ToString() + ",");
            else if (Value is MM_Boundary)
                xW.WriteAttributeString(Name, (Value as MM_Boundary).Name);
            else if (Value is MM_Zone)
                xW.WriteAttributeString(Name, (Value as MM_Zone).Index.ToString());
            else if (Value is MM_Element)
                xW.WriteAttributeString(Name, (Value as MM_Element).TEID.ToString());
            else if (Value is String)
                xW.WriteAttributeString(Name, (String)Value);
            else if (Value is UInt64)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is Int32)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is Color)
                xW.WriteAttributeString(Name, ColorTranslator.ToHtml((Color)Value));
            else if (Value is Pen)
                xW.WriteAttributeString(Name, ColorTranslator.ToHtml(((Pen)Value).Color) + "," + ((Pen)Value).Width);
            else if (Value is Single)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is bool)
                xW.WriteAttributeString(Name, XmlConvert.ToString((bool)Value));
            else if (Value is DateTime)
                xW.WriteAttributeString(Name, XmlConvert.ToString((DateTime)Value, XmlDateTimeSerializationMode.Unspecified));
            else if (Value is MM_KVLevel)
                xW.WriteAttributeString(Name, (Value as MM_KVLevel).Name);
            else if (Value is MM_Event_Type)
                xW.WriteAttributeString(Name, (Value as MM_Event_Type).Name);
            else if (Value is MM_Element_Type)
                xW.WriteAttributeString(Name, (Value as MM_Element_Type).Name);
            else if (Value is MM_Display_Parameter)            
                WriteAttributes(xW, Value, Name);            
            else if (Value is System.Windows.Forms.ListViewItem)
                xW.WriteAttributeString(Name, (Value as System.Windows.Forms.ListViewItem).Text);
            else if (Value is MM_Generation_Type)
                xW.WriteAttributeString(Name, (Value as MM_Generation_Type).Name);
            else if (Value is System.Windows.Forms.Label)
                xW.WriteAttributeString(Name, (Value as System.Windows.Forms.Label).Text);
            else if (Value is MM_Element_Type)
            { }
            else if (Value is IEnumerable<PointF>)
            {
                StringBuilder sB = new StringBuilder();
                foreach (PointF Pt in (IEnumerable<PointF>)Value)
                    sB.Append(sB.Length != 0 ? "," + Pt.X.ToString() + "," + Pt.Y.ToString() : Pt.X.ToString() + "," + Pt.Y.ToString());
                xW.WriteAttributeString(Name, sB.ToString());
            }
            else if (Value is MM_Communication.ConnectionStateEnum)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is System.Collections.IDictionary)
            {
                StringBuilder sB = new StringBuilder();
                foreach (System.Collections.DictionaryEntry Entry in (System.Collections.IDictionary)Value)
                    sB.Append(sB.Length != 0 ? "," + Entry.Key.ToString() : Entry.Key.ToString());
                xW.WriteAttributeString(Name, sB.ToString());
            }
            else if (Value is System.Collections.IEnumerable)
            {
                StringBuilder sB = new StringBuilder();
                foreach (Object inStr in (System.Collections.IEnumerable)Value)
                    if (inStr is MM_Element)
                        sB.Append((sB.Length != 0 ? "," : "") + (inStr as MM_Element).TEID.ToString());
                    else
                        sB.Append(sB.Length != 0 ? "," + inStr.ToString() : inStr.ToString());
                xW.WriteAttributeString(Name, sB.ToString());
            }
            else if (Value is MM_Zone)
                xW.WriteAttributeString(Name, (Value as MM_Zone).Name);
            else if (Value.GetType().IsEnum)
                xW.WriteAttributeString(Name, Value.ToString());
            else if (Value is System.Windows.Forms.Control)
                foreach (PropertyInfo pI in Value.GetType().GetProperties())
                {
                    Object CurValue = pI.GetValue(Value, null);
                    if (pI.Name.Contains("Parent"))
                        Console.WriteLine("");
                    bool NeedsUpdate = true;
                    foreach (object attr in pI.GetCustomAttributes(true))
                        if (attr is DefaultValueAttribute && (attr as DefaultValueAttribute).Value == CurValue)
                            NeedsUpdate = false;
                        else if (attr is DesignerSerializationVisibilityAttribute && (attr as DesignerSerializationVisibilityAttribute).Visibility == DesignerSerializationVisibility.Hidden)
                            NeedsUpdate = false;
                    if (NeedsUpdate)
                        WriteXMLData("Descriptor" + pI.Name, CurValue, xW);
                }
            else
            { }// Console.WriteLine("Unable to handle type " + Value.GetType().Name);
        }
    }
}
